package top.usts.springframework.context.support;

import top.usts.springframework.beans.BeansException;
import top.usts.springframework.beans.factory.ConfigureableListableBeanFactory;
import top.usts.springframework.beans.factory.config.BeanFactoryPostProcessor;
import top.usts.springframework.beans.factory.config.BeanPostProcessor;
import top.usts.springframework.context.ApplicationEvent;
import top.usts.springframework.context.ApplicationListener;
import top.usts.springframework.context.ConfigurableApplicationContext;
import top.usts.springframework.context.event.ApplicationEventMulticaster;
import top.usts.springframework.context.event.ContextClosedEvent;
import top.usts.springframework.context.event.ContextRefreshedEvent;
import top.usts.springframework.context.event.SimpleApplicationEventMulticaster;
import top.usts.springframework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;


/**
 * @description:
// * Abstract implementation of the {@link top.usts.springframework.context.ApplicationContext}
 * interface. Doesn't mandate the type of storage used for configuration; simply
 * implements common context functionality. Uses the
 *
 * Template Method design pattern, 模板设计模式
 * requiring concrete subclasses to implement abstract methods.
 * <p>
 * 抽象应用上下文
 * @author: CJ
 * @date: 2022/2/23
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        //1 创建 BeanFactory 并加载 BeanDefinition
        refreshBeanFactory();
        //2 获取 BeanFactory
        ConfigureableListableBeanFactory beanFactory = getBeanFactory();
        //3  添加applicationContextAwareProcessor 让继承ApplicationContextAware 的 bean对象都能感知所属的 applicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        //4 在 Bean 实例化之前，执行 BeanFactoryPostProcess
        invokeBeanFactoryPostProcessors(beanFactory);

        //5 BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        //6 初始化事件发布者
        initApplicationEventMulticaster();

        //7 注册事件监听器
        registerListeners();

        //8 提前实例化单例对象
        beanFactory.preInstantiateSingletons();

        //9 发布容器刷新完成事件
        finishRefresh();

    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    private void initApplicationEventMulticaster() {
        ConfigureableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }


    private void invokeBeanFactoryPostProcessors(ConfigureableListableBeanFactory beanFactory) {
        //取出所有继承BeanFactoryPostProcessor的类
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }


    private void registerBeanPostProcessors(ConfigureableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigureableListableBeanFactory getBeanFactory();

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name,args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> typeClass) throws BeansException {
        return getBeanFactory().getBeansOfType(typeClass);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        //发布容器关闭四件
        publishEvent(new ContextClosedEvent(this));

        //执行销毁单利bean的销毁方法
        getBeanFactory().destroySingletons();
    }
}
